<?php
// 获取
function getCateMenuToChild (&$cate, $hide_cate)
{
    foreach ($cate as $key => &$value)
    {
        $value['url'] = ! empty($value['_child']) ? '' : U('Document/index?category_id=' . $value['id']);
        empty($value['_child']) or getCateMenuToChild($value['_child'], $hide_cate);
    }
}

function getBreadCrumb ()
{
    $menus = M('Menu')->order('sort asc')->cache()->select();
    $path = array();
    $Auth = new \Kcdns\Common\Common\AuthExtend();
    $current = $Auth->findMenu();
    $Auth->findRulePath($menus, $current ? $current['id'] : false, $path);
    if ($path)
    {
        $length = count($path);
        // path最后一级为分组 设置隐藏标记
        if ($path[$length - 1]['is_group'])
        {
            $path[$length - 1]['is_hidden'] = true;
        }
        else
        {
            $path[count($path) - 1]['url'] = '#';
        }
    }
    return $path;
}

/**
 * 清理没有在菜单树中出现的无效节点
 */
function clearMenu ()
{
    if (! function_exists('_getMenuTreeIds'))
    {

        function _getMenuTreeIds ($tree)
        {
            $ids = array();
            foreach ($tree as $k => $v)
            {
                $ids[] = $v['id'];
                $v['_child'] and $ids = array_merge($ids, _getMenuTreeIds($v['_child']));
            }
            return $ids;
        }
    }
    
    M('menu')->where(array(
            'id' => array(
                    'NOT IN',
                    _getMenuTreeIds(list_to_tree(M('Menu')->field(true)->order('sort asc')->select()))
            )
    ))->delete();
}

/**
 * 获取用户菜单树
 * 每个用户使用不同缓存
 * TODO 使用用户所有的角色ID查询缓存
 */
function getMenus ()
{
    $cacheKey = 'ADMIN_MENU_CACHE_' . UID;
    $menu = S($cacheKey);
    if (! $menu)
    {
        $where = [
                'status' => 1,
                'hide' => 0
        ];
        is_administrator() or $where['is_dev'] = 0;
        $list = M('menu')->where($where)->order('sort asc')->select();
        $menu = list_to_tree($list, 'id', 'pid');
        $i = 1;
        foreach ($menu as $k => &$v)
        {
            //if (checkRule($v['url']) === false || ! $v['title'] || ! $v['url'])
            if ( ! $v['title'] )
            {
                unset($menu[$k]);
                continue;
            }
            $v['href'] = U($v['url']);
            
            $v['child'] = [];
            $v['_child'] = $v['_child']?:[];
            foreach ($v['_child'] as $kk => &$vv)
            {
                if (checkRule($vv['url']) === false || ! $vv['title'] || ! $vv['url'])
                {
                    unset($menu[$k]['_child'][$kk]);
                    continue;
                }
                $vv['href'] = U($vv['url']);
                
                $vv['_child'] = $vv['_child']?:[];
                foreach ($vv['_child'] as $kkk => &$vvv)
                {
                    if (checkRule($vvv['url']) === false || ! $vvv['title'] || ! $vvv['url'])
                    {
                        unset($menu[$k]['_child'][$kk]['_child'][$kkk]);
                        continue;
                    }
                    $vvv['href'] = U($vvv['url']);
                }
                $vv['child'] = $vv['_child'];
                unset($v['_child'][$kk]['_child']);
                
                $vv['group'] ? $v['child'][$vv['group']][] = $vv : $v['child'][$i ++] = $vv;
            }
            unset($menu[$k]['_child']);
            if(!$v['child']){
                unset($menu[$k]);
            }
        }
        $menu = array_values($menu);
        S($cacheKey, $menu);
    }
    return $menu;
}

/**
 * 后台节点配置的url作为规则存入auth_rule
 * 1.插入执行新节点
 * 2.更新已有节点
 * 3.删除无效规则
 * 4.赋予开发者账号全部权限
 * 5.创建快速查询缓存
 */
function syncAuthNodes ()
{
    $AuthRule = M('AuthRule');
    
    // 所有权限节点
    $rules = $AuthRule->where(array(
            'module' => 'admin',
            'type' => array(
                    'in',
                    '1,2'
            )
    ))->order('name')->select();
    
    // 所有菜单节点
    $nodes = getAuthNodes(false, true);
    
    $data = array(); // 保存需要插入和更新的新节点
    foreach ($nodes as $value)
    {
        $temp['name'] = $value['url'];
        $temp['title'] = $value['title'];
        $temp['module'] = 'admin';
        $temp['type'] = $value['pid'] > 0 ? 1 : 2;
        $temp['status'] = 1;
        $data[strtolower($temp['name'] . $temp['module'] . $temp['type'])] = $temp; // 去除重复项
    }
    
    $update = array(); // 保存需要更新的节点
    $ids = array(); // 保存需要删除的节点的id
    foreach ($rules as $index => $rule)
    {
        $key = strtolower($rule['name'] . $rule['module'] . $rule['type']);
        // 如果数据库中的规则与配置的节点匹配,说明是需要更新的节点
        if (isset($data[$key]))
        {
            $data[$key]['id'] = $rule['id']; // 为需要更新的节点补充id值
            $update[] = $data[$key];
            unset($data[$key]);
            unset($rules[$index]);
            unset($rule['condition']);
            $diff[$rule['id']] = $rule;
        }
        elseif ($rule['status'] == 1)
        {
            // 菜单中已删除 权限节点对应需删除
            $ids[] = $rule['id'];
        }
    }
    
    if (count($update))
    {
        foreach ($update as $k => $row)
        {
            if ($row != $diff[$row['id']])
            {
                $AuthRule->where(array(
                        'id' => $row['id']
                ))->save($row);
            }
        }
    }
    
    count($ids) and $AuthRule->where(array(
            'id' => array(
                    'IN',
                    implode(',', $ids)
            )
    ))->delete();
    $AuthRule->where(array(
            'status' => '-1'
    ))->delete();
    
    count($data) and $AuthRule->addAll(array_values($data));
    
    syncAuthAdmin();
}

/**
 * 获取所有授权规则
 *
 * @param string $tree            
 * @param string $showDev            
 */
function getAuthNodes ($tree = true, $showDev = false)
{
    $where = ['status' => 1];
    $showDev or $where['is_dev'] = 0;
    $nodes = M('Menu')->where($where)->field('id,pid,title,url,tip,hide')->order('sort asc')->select();
    foreach ($nodes as $key => $value)
    {
        if (stripos($value['url'], MODULE_NAME) !== 0)
        {
            $nodes[$key]['url'] = MODULE_NAME . '/' . $value['url'];
        }
    }
    
    if ($tree)
    {
        $nodes = list_to_tree($nodes, $pk = 'id', $pid = 'pid', $child = 'operator', $root = 0);
        foreach ($nodes as $key => $value)
        {
            if (! empty($value['operator']))
            {
                $nodes[$key]['child'] = $value['operator'];
                unset($nodes[$key]['operator']);
            }
        }
    }
    
    return $nodes;
}

/**
 * 同步超级管理员权限
 * 超级管理员组拥有所有可分配权限
 */
function syncAuthAdmin ()
{
    
    // 所有权限
    $allRules = M('AuthRule')->where(array(
            'module' => 'admin',
            'status' => 1
    ))->field('id')->select();
    foreach ($allRules as $v)
    {
        $ids[] = $v['id'];
    }
    
    // 创建或者更新开发者组
    $data = array(
            'module' => 'admin',
            'type' => 0,
            'title' => '开发者',
            'status' => 1,
            'description' => '仅开发者账号可见',
            'rules' => implode(',', $ids)
    );
    $where = array(
            'module' => 'admin',
            'type' => 0
    );
    $model = M('auth_group');
    $group = $model->where($where)->find();
    
    if ($group)
    {
        $st = $model->where($where)->data($data)->save();
    }
    else
    {
        $group['id'] = $model->data($data)->add();
    }
    
    // 将超级管理员添加到开发者组, 将其他管理员移出开发者组
    $rootId = C('USER_ADMINISTRATOR');
    $gModel = M('auth_group_access');
    $gModel->where(array(
            "uid" => array(
                    'neq',
                    $rootId
            ),
            'group_id' => $group['id']
    ))->delete();
    ! $gModel->where(array(
            'uid' => $rootId,
            'group_id' => $group['id']
    ))->select() && $gModel->data(array(
            'uid' => $rootId,
            'group_id' => $group['id']
    ))->add();
    
    // 赋予所有分类权限
    $categorys = M('category')->where()->field('id')->select();
    foreach ($categorys as $v)
    {
        $cids[] = $v['id'];
    }
    \Kcdns\Admin\Model\AuthGroupModel::addToExtend($group['id'], $cids, \Kcdns\Admin\Model\AuthGroupModel::AUTH_EXTEND_CATEGORY_TYPE);
}

/**
 * 检查 URL 访问权限
 *
 * @param string $url            
 */
function checkRule ($url)
{
    static $authRule = [];
    isset($authRule[UID]) or $authRule[UID] = getUserAuthList();
    
    // 只提取 path 部分进行验证, 忽略参数
    list ($path, $param) = explode('?', $url);
    $mca = explode('/', $path);
    switch (count($mca))
    {
        case 3:
            // 错误的配置, 尝试修复
            // Mname/Cname/Aname => Adnim/Cname/Aname
            $mca[0] = MODULE_NAME;
            break;
        case 2:
            // 正确的配置, 菜单中必须使用此格式
            // Cname/Aname => Admin/Cname/Aname
            array_unshift($mca, MODULE_NAME);
            break;
        case 1:
            // 正确的配置, cfg 中可以使用, 动态监测, 按照当前控制器补全路径
            // Aname => Admin/Cname/Aname
            array_unshift($mca, CONTROLLER_NAME);
            array_unshift($mca, MODULE_NAME);
            break;
        default:
            return false;
    }
    $rule = strtolower(implode('/', $mca));
    return in_array($rule, $authRule[UID]);
}

/**
 * 获取当前用户的权限列表
 *
 * @param $type string
 *            权限列表类型 1：url 2:主菜单
 */
function getUserAuthList ()
{
    $userAuthList = S('AUTH_LIST_' . UID);
    if (! $userAuthList)
    {
        $userAuthList = (new \Kcdns\Common\Common\AuthExtend())->getAuthList(UID, 1); // 自己有权限的节点列表
        S('AUTH_LIST_' . UID, $userAuthList);
    }
    return $userAuthList;
}

function menuOptions($data){

    isset($data['id']) and $data['id'] and $where = [
            'id' => [
                    'neq',
                    $data['id']
            ],
            'pid' => [
                    'neq',
                    $data['id']
            ]
    ];
    
    $rootNodes = M('menu')->where(['pid'=>0])->field('id')->select();
    $w = [0];
    foreach($rootNodes as $v){
        $w[] = $v['id'];
    }
    $whereString = "pid in ('".implode("','", $w)."')";
    
    $menu = M('menu')->where($where)->where($whereString)->field('id,title,pid')->order('pid,sort')->select();
    
    
    return getTreeSelectArray(array(
            array(
                    'id' => 0,
                    'title' => '后台菜单',
                    '_child' => list_to_tree($menu)
            )
    ));
    
}